package com.bbf.springmvcdemo.interceptor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.NamedThreadLocal;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 日志拦截器
 * @author BBF
 */
public final class LogInterceptor implements HandlerInterceptor {
  private static final Logger LOGGER = LoggerFactory.getLogger(LogInterceptor.class);

  private static final ThreadLocal<Long> START_TIME_THREADLOCAL = new NamedThreadLocal<>(
      "ThreadLocal StartTime");

  @Override
  public boolean preHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler) {
    // 线程绑定变量（该数据只有当前请求的线程可见）
    START_TIME_THREADLOCAL.set(System.currentTimeMillis());
    return true;
  }

  @Override
  public void postHandle(HttpServletRequest request,
                         HttpServletResponse response,
                         Object handler,
                         ModelAndView modelAndView) {
    if (LOGGER.isDebugEnabled() && modelAndView != null) {
      LOGGER.debug("视图名称: {}", modelAndView.getViewName());
    }
  }

  @Override
  public void afterCompletion(HttpServletRequest request,
                              HttpServletResponse response,
                              Object handler,
                              Exception ex) {
    // 打印JVM信息
    if (LOGGER.isDebugEnabled()) {
      // 得到线程绑定的局部变量（开始时间）
      long beginTime = START_TIME_THREADLOCAL.get();
      long endTime = System.currentTimeMillis();
      long memMax = Runtime.getRuntime().maxMemory();
      long memTotal = Runtime.getRuntime().totalMemory();
      long memFree = Runtime.getRuntime().freeMemory();
      LOGGER.debug("行为拦截器，URI: {}，耗时：{}ms，URI: {}，最大内存: {}，已分配内存: {}，已分配内存中的剩余空间: {}，最大可用内存: {}",
          request.getRequestURI(),
          endTime - beginTime, request.getRequestURI(),
          byteCountToDisplaySize(memMax), byteCountToDisplaySize(memTotal),
          byteCountToDisplaySize(Runtime.getRuntime().freeMemory()),
          byteCountToDisplaySize(memMax - memTotal + memFree));
    }
    START_TIME_THREADLOCAL.remove();
  }

  /**
   * 计算KB
   * @param size 字节数
   * @return 显示XX MB
   */
  private static String byteCountToDisplaySize(long size) {
    // 1024 * 1024 = 1048576
    return String.format("%.2fMB", size / 1048576F);
  }
}
